/**
 * Author(s): xuming.Wong <xuming.Wong@gmail.com>
 */
#include "IMECHSWin.h"

#if PLATFORM == PLATFORM_WINDOWS

#include <Imm.h>
#pragma comment(lib, "Imm32.lib")

#include "PQException.h"

namespace PQClient
{
	bool IMECHSWin::_isOK = false;
	bool IMECHSWin::_isLock = false;
	WNDPROC IMECHSWin::_funcWndProc = NULL;

	LRESULT IMECHSWin::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
	{
		switch( uMsg ){
		case WM_IME_COMPOSITION:
			{
				if( lParam & GCS_COMPSTR ){
					HIMC hIMC = ImmGetContext( hWnd );
					TCHAR szBuf[1280] = {0};
					DWORD dwSize = ImmGetCompositionString( hIMC, GCS_COMPSTR, (void*)szBuf, 1280 );
					if( dwSize != 0 ){
						_isLock = true;
					}else{
						_isLock = false;
					}
				}
			}

			break;

		case WM_CHAR :
			{
				MakeWChar((CEGUI::utf32)wParam);
			}
			break;
		}

		return CallWindowProc( _funcWndProc , hWnd , uMsg , wParam , lParam );
	}

	bool IMECHSWin::MakeWChar( unsigned char code )
	{
		using namespace CEGUI;

		static char     s_tempChar[3]  = "";
		static wchar_t  s_tempWchar[2] = L"";

		static bool s_flag = false;

		unsigned char  uch  = code;

		if( uch >= 0x81 || s_flag ){
			if( !s_flag ){
				s_tempChar[0] = (char)uch;
				s_flag = true;
				return true;
			}else if(  uch >= 0x40 ){
				s_tempChar[1] = (char)uch; 
				s_flag = false;
				MultiByteToWideChar( 0, 0, s_tempChar, 2, s_tempWchar, 1);

				s_tempWchar[1] = L'\0';

				utf32 code = (utf32)s_tempWchar[0];

				return CEGUI::System::getSingleton().injectChar( code );
			}else{
				if ( !ImmIsIME(GetKeyboardLayout(0))) {
					return CEGUI::System::getSingleton().injectChar(code);
				}
			}
		}else{
			s_flag = false;
			return CEGUI::System::getSingleton().injectChar(code);
		}

		return false;
	}

	bool IMECHSWin::injectChar( Ogre::RenderWindow* window, uint32 code )
	{
		if( !_isOK ){
			HWND hWnd = NULL;
			window->getCustomAttribute( "WINDOW", &hWnd );

			if( NULL == hWnd ){
				throw std::runtime_error( "error on windows handle..." );
			}

			_funcWndProc = (WNDPROC)::GetWindowLong( hWnd, GWL_WNDPROC );
			::SetWindowLong(hWnd, GWL_WNDPROC, (LONG)WndProc );

			_isOK = true;
			return false;
		}

		return true;
	}
}
#endif
